"""
认证工具函数 (utils/auth_utils.py)

提供用户认证相关功能，包括密码哈希生成和验证。
"""
import bcrypt
import uuid
import jwt
import datetime
from flask import current_app, request, jsonify, g
from functools import wraps
import logging

def hash_password(password):
    """
    对密码进行哈希加密。
    使用bcrypt算法加盐哈希，安全存储用户密码。
    
    Args:
        password: 明文密码
        
    Returns:
        str: 密码哈希值
    """
    try:
        # 生成盐值并哈希密码
        password_bytes = password.encode('utf-8')
        salt = bcrypt.gensalt()
        hashed = bcrypt.hashpw(password_bytes, salt)
        return hashed.decode('utf-8')
    except Exception as e:
        logger = logging.getLogger(__name__)
        logger.error(f"密码哈希生成失败: {str(e)}")
        raise

def check_password(password, hashed_password):
    """
    验证密码是否匹配哈希值。
    
    Args:
        password: 待验证的明文密码
        hashed_password: 存储的密码哈希值
        
    Returns:
        bool: 密码匹配返回True，否则返回False
    """
    try:
        password_bytes = password.encode('utf-8')
        hashed_bytes = hashed_password.encode('utf-8')
        return bcrypt.checkpw(password_bytes, hashed_bytes)
    except (ValueError, TypeError) as e:
        logger = logging.getLogger(__name__)
        logger.error(f"密码验证出错: {str(e)}")
        return False

def generate_token(user_id, username, role, expires_in=86400):
    """
    生成JWT认证令牌。
    
    Args:
        user_id: 用户ID
        username: 用户名
        role: 用户角色
        expires_in: 过期时间(秒)，默认24小时
        
    Returns:
        str: JWT令牌
    """
    # 设置令牌过期时间
    expiration = datetime.datetime.utcnow() + datetime.timedelta(seconds=expires_in)
    
    # 创建令牌载荷
    payload = {
        'sub': user_id,
        'username': username,
        'role': role,
        'exp': expiration,
        'iat': datetime.datetime.utcnow(),
        'jti': str(uuid.uuid4())  # 唯一令牌ID
    }
    
    # 获取密钥 - 根据实际情况设置密钥
    secret_key = current_app.config.get('SECRET_KEY', 'memeking-secret-key')
    
    # 生成JWT令牌
    token = jwt.encode(payload, secret_key, algorithm='HS256')
    
    return token

def decode_token(token):
    """
    解码和验证JWT令牌。
    
    Args:
        token: JWT令牌
        
    Returns:
        dict: 包含用户信息的字典，如果令牌无效则返回None
    """
    try:
        # 获取密钥
        secret_key = current_app.config.get('SECRET_KEY', 'memeking-secret-key')
        
        # 解码令牌
        payload = jwt.decode(token, secret_key, algorithms=['HS256'])
        return payload
    except jwt.ExpiredSignatureError:
        # 令牌已过期
        return None
    except jwt.InvalidTokenError:
        # 令牌无效
        return None

def auth_required(f):
    """
    权限验证装饰器，要求请求包含有效的JWT令牌。
    将解码后的用户ID存储在g.user_id中。
    
    使用方式:
    @app.route('/protected')
    @auth_required
    def protected_route():
        # 通过g.user_id访问用户ID
        return f"Hello user {g.user_id}"
    """
    @wraps(f)
    def decorated(*args, **kwargs):
        # 从Authorization头部获取令牌
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return jsonify({"error": "未提供认证令牌或格式错误"}), 401
        
        # 提取令牌
        token = auth_header.split(' ')[1]
        
        # 解码令牌
        payload = decode_token(token)
        if not payload:
            return jsonify({"error": "无效或已过期的令牌"}), 401
        
        # 将用户ID存储在g对象中
        g.user_id = payload['sub']
        g.username = payload.get('username')
        g.role = payload.get('role')
        
        return f(*args, **kwargs)
    return decorated 